package com.example.grape_effect.effet.filter

import android.opengl.GLES20
import com.example.grape_effect.base.GrapeEffect
import com.example.grape_effect.gl.common.ShaderConstant
import com.example.grape_effect.gl.common.ShaderParameter



class FaceBeautyFilter: LYFilter() {
    init {
        name = "faceBeautyFilter"
    }
    override var vertexShader ="""
        attribute vec4 vPosition;
        attribute vec2 vInputTextureCoordinate;
        varying vec2 textureCoordinate;
        varying vec2 blurCoord1s[14];
        const highp float mWidth=1080.0;
        const highp float mHeight=1440.0;
        void main( )
        {
            gl_Position = vPosition;//vMatrix*
            textureCoordinate = vInputTextureCoordinate;

            highp float mul_x = 2.0 / mWidth;
            highp float mul_y = 2.0 / mHeight;

            // 14个采样点
            blurCoord1s[0] = vInputTextureCoordinate + vec2( 0.0 * mul_x, -10.0 * mul_y );
            blurCoord1s[1] = vInputTextureCoordinate + vec2( 8.0 * mul_x, -5.0 * mul_y );
            blurCoord1s[2] = vInputTextureCoordinate + vec2( 8.0 * mul_x, 5.0 * mul_y );
            blurCoord1s[3] = vInputTextureCoordinate + vec2( 0.0 * mul_x, 10.0 * mul_y );
            blurCoord1s[4] = vInputTextureCoordinate + vec2( -8.0 * mul_x, 5.0 * mul_y );
            blurCoord1s[5] = vInputTextureCoordinate + vec2( -8.0 * mul_x, -5.0 * mul_y );
            blurCoord1s[6] = vInputTextureCoordinate + vec2( 0.0 * mul_x, -6.0 * mul_y );
            blurCoord1s[7] = vInputTextureCoordinate + vec2( -4.0 * mul_x, -4.0 * mul_y );
            blurCoord1s[8] = vInputTextureCoordinate + vec2( -6.0 * mul_x, 0.0 * mul_y );
            blurCoord1s[9] = vInputTextureCoordinate + vec2( -4.0 * mul_x, 4.0 * mul_y );
            blurCoord1s[10] = vInputTextureCoordinate + vec2( 0.0 * mul_x, 6.0 * mul_y );
            blurCoord1s[11] = vInputTextureCoordinate + vec2( 4.0 * mul_x, 4.0 * mul_y );
            blurCoord1s[12] = vInputTextureCoordinate + vec2( 6.0 * mul_x, 0.0 * mul_y );
            blurCoord1s[13] = vInputTextureCoordinate + vec2( 4.0 * mul_x, -4.0 * mul_y );
        }
    """.trimIndent()
    override var fragmentShader = """
        precision lowp float;
        precision lowp int;
        uniform sampler2D inputTexture;
        uniform int iternum;
        uniform float aaCoef; //参数
        uniform float mixCoef; //混合系数
        varying highp vec2 textureCoordinate;
        varying highp vec2 blurCoord1s[14];
        const float distanceNormalizationFactor = 4.0;    //标准化距离因子常量
        const mat3 saturateMatrix = mat3(1.1102,-0.0598,-0.061,-0.0774,1.0826,-0.1186,-0.0228,-0.0228,1.1772);

        void main( ) {

            vec3 centralColor;
            float central;
            float gaussianWeightTotal;
            float sum;
            float sampleColor;
            float distanceFromCentralColor;
            float gaussianWeight;

            //通过绿色通道来磨皮
            //取得当前点颜色的绿色通道
            central = texture2D( inputTexture, textureCoordinate ).g;
            //高斯权重
            gaussianWeightTotal = 0.2;
            //绿色通道色彩记数
            sum = central * 0.2;

            // 计算各个采样点处的高斯权重，包括密闭性和相似性
            for (int i = 0; i < 6; i++) {
                //采样点的绿色通道
                sampleColor = texture2D( inputTexture, blurCoord1s[i] ).g;
                //采样点和计算点的颜色差
                distanceFromCentralColor = min( abs( central - sampleColor ) * distanceNormalizationFactor, 1.0 );
                //高斯权重
                gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
                //高斯权重总和
                gaussianWeightTotal += gaussianWeight;
                //绿色通道色彩记数累计
                sum += sampleColor * gaussianWeight;
            }
            for (int i = 6; i < 14; i++) {
                //采样点的绿色通道
                sampleColor = texture2D( inputTexture, blurCoord1s[i] ).g;
                //采样点和计算点的颜色差
                distanceFromCentralColor = min( abs( central - sampleColor ) * distanceNormalizationFactor, 1.0 );
                //高斯权重
                gaussianWeight = 0.1 * (1.0 - distanceFromCentralColor);
                //高斯权重总和
                gaussianWeightTotal += gaussianWeight;
                //绿色通道色彩记数累计
                sum += sampleColor * gaussianWeight;
            }

            //采样后的绿色通道色彩均值
            sum = sum / gaussianWeightTotal;

            //取得当前点的颜色
            centralColor = texture2D( inputTexture, textureCoordinate ).rgb;
            //采样值
            sampleColor = centralColor.g - sum + 0.5;
            //迭代计算
            for (int i = 0; i < iternum; ++i) {
                if (sampleColor <= 0.5) {
                    sampleColor = sampleColor * sampleColor * 2.0;
                }else {
                    sampleColor = 1.0 - ((1.0 - sampleColor)*(1.0 - sampleColor) * 2.0);
                }
            }

            float aa = 1.0 + pow( centralColor.g, 0.3 )*aaCoef;
            vec3 smoothColor = centralColor*aa - vec3( sampleColor )*(aa - 1.0);
            smoothColor = clamp( smoothColor, vec3( 0.0 ), vec3( 1.0 ) );
            smoothColor = mix( centralColor, smoothColor, pow( centralColor.g, 0.33 ) );
            smoothColor = mix( centralColor, smoothColor, pow( centralColor.g, mixCoef ) );
            gl_FragColor = vec4( pow( smoothColor, vec3( 0.96 ) ), 1.0 );
            vec3 satcolor = gl_FragColor.rgb * saturateMatrix;
            gl_FragColor.rgb = mix( gl_FragColor.rgb, satcolor, 0.23 );

        }
    """.trimIndent()

    override fun addParameters() {
        parameters["vPosition"] = ShaderParameter(
            "vPosition",
            ShaderParameter.TYPE_ATTRIBUTE,
            ShaderParameter.VALUE_TYPE_ATTRIBUTE_PARAMETER
        )
        parameters["vInputTextureCoordinate"] = ShaderParameter(
            "vInputTextureCoordinate",
            ShaderParameter.TYPE_ATTRIBUTE,
            ShaderParameter.VALUE_TYPE_ATTRIBUTE_PARAMETER
        )
        parameters["inputTexture"] = ShaderParameter(
            "inputTexture",
            ShaderParameter.TYPE_TEXTURE,
            ShaderParameter.VALUE_TYPE_IMAGE_TEXTURE
        )

        parameters["iternum"] = ShaderParameter(
            "iternum",
            ShaderParameter.TYPE_UNIFORM,
            ShaderParameter.VALUE_TYPE_INT
        )
        parameters["aaCoef"] = ShaderParameter(
            "aaCoef",
            ShaderParameter.TYPE_UNIFORM,
            ShaderParameter.VALUE_TYPE_FLOAT
        )
        parameters["mixCoef"] = ShaderParameter(
            "mixCoef",
            ShaderParameter.TYPE_UNIFORM,
            ShaderParameter.VALUE_TYPE_FLOAT
        )
    }

    override fun setDefaultParameterValues() {
        parameters["vPosition"]?.value = ShaderParameter.AttributeParameter(ShaderConstant.POSITIONS, 2)
        parameters["vInputTextureCoordinate"]?.value = ShaderParameter.AttributeParameter(
            ShaderConstant.COORDINATE, 2)
        parameters["inputTexture"]?.value = GrapeEffect.testInTexture

        parameters["iternum"]?.value = 0
        parameters["aaCoef"]?.value = 0f
        parameters["mixCoef"]?.value = 0f

    }
    private fun setBeautyProgress(a:Int,b:Float,c:Float) {
        parameters["iternum"]?.value = a
        parameters["aaCoef"]?.value = b
        parameters["mixCoef"]?.value = c
    }

    private fun updateParameters(progress: Int) {
        when (progress) {
            1 -> setBeautyProgress(1, 0.19f, 0.54f);
            2 -> setBeautyProgress(2, 0.29f, 0.54f);
            3 -> setBeautyProgress(3, 0.17f, 0.39f);
            4 -> setBeautyProgress(3, 0.25f, 0.54f);
            5 -> setBeautyProgress(4, 0.13f, 0.54f);
            6 -> setBeautyProgress(4, 0.19f, 0.69f);
            7 -> setBeautyProgress(5, 0.3f, 0.9f);
            else -> setBeautyProgress(0, 0f, 0f);
        }
    }


    // must use in glThread
    override fun draw() {
        updateParameters(3)
        clearColor()
        initProgram()
        GLES20.glUseProgram(program)
        setParametersToShader()
        GLES20.glEnableVertexAttribArray(parameters["vPosition"]!!.location)
        GLES20.glEnableVertexAttribArray(parameters["vInputTextureCoordinate"]!!.location)
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
        GLES20.glDisableVertexAttribArray(parameters["vPosition"]!!.location)
        GLES20.glDisableVertexAttribArray(parameters["vInputTextureCoordinate"]!!.location)
    }

}